﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CalculateModelClasses;
using UanFileProceed;

namespace RayTracingModel
{
    public class RayPath
    {
        //私有函数
        #region
        //求射线与接收球的交点,使用之前保证发射点与节点的距离大于接收球半径

        public static List<Point> IsIntersectWithBall(RayInfo ray, ReceiveBall receive)
        {
            List<Point> crosspoints = new List<Point>();
            Point crosspoint;
            double A, B, C, t;
            A = Math.Pow(ray.RayVector.Mag(), 2);
            B = 2 * (ray.RayVector.a * (ray.origin.x - receive.receiver.x) + ray.RayVector.b * (ray.origin.y - receive.receiver.y) + ray.RayVector.c * (ray.origin.z - receive.receiver.z));
            C = Math.Pow(Intersection.Distance(ray.origin, receive.receiver), 2) - receive.radius * receive.radius;
            double temp = B * B - 4 * A * C;
            if (temp < 0) return crosspoints;
            else if (temp == 0)
            {
                t = -(B / (2 * A));
                crosspoint = new Point(ray.RayVector.a * t + ray.origin.x, ray.RayVector.b * t + ray.origin.y, ray.RayVector.c * t + ray.origin.z);
                crosspoints.Add(crosspoint);
                return crosspoints;
            }
            else
            {
                t = (-B + Math.Sqrt(temp)) / (2 * A);
                crosspoint = new Point(ray.RayVector.a * t + ray.origin.x, ray.RayVector.b * t + ray.origin.y, ray.RayVector.c * t + ray.origin.z);
                crosspoints.Add(crosspoint);
                t = (-B - Math.Sqrt(temp)) / (2 * A);
                crosspoint = new Point(ray.RayVector.a * t + ray.origin.x, ray.RayVector.b * t + ray.origin.y, ray.RayVector.c * t + ray.origin.z);
                crosspoints.Add(crosspoint);
                return crosspoints;
            }
        }

        //求离发射源最近的交点

        private static Point NearPoint(List<Point> p, RayInfo ray)
        {
            if (p.Count == 1) return p[0];
            else if (p.Count == 2)
            {
                if (Intersection.Distance(p[0], ray.origin) < Intersection.Distance(p[1], ray.origin))
                    return p[0];
                else return p[1];
            }
            else return null;
        }

        //判断射线是先到达接收点还是先到达地形面

        private static bool ArriveReceiveFirst(Point origin, Point TerPoint, Point BallPoint)
        {
            if (BallPoint == null) return false;
            else if (Intersection.OnLine(origin, TerPoint, BallPoint, 0)) return true;
            else return false;
        }

        //根据点类型发射射线

        private static List<RayInfo> GetRays(Node child, Node father, double DiffractionAngle)
        {
            List<RayInfo> rays = new List<RayInfo>();
            switch (child.PointStyle)
            {
                case "Tx":
                    //直射射线采用读文件方式发射
                    rays = Rays.TxRays(child.Position);
                    break;
                case "ReflectionPoint":
                    rays = Rays.ReflectionRays(father.Position, child.Position, child.ReflectionFace);
                    break;
                case "DiffractionPoint":
                    rays = Rays.DiffractionRays(child.Linea, child.Lineb, child.Position, child.RayIn, child.DiffractionFaces, DiffractionAngle);
                    break;
                default:
                    break;
            }
            return rays;
        }

        //根据点类型获得电场值

        private static void GetEfield(string uan, Node child, ref Node temp)
        {
            switch (child.PointStyle)
            {
                case "Tx":
                    //直射场强计算
                    temp.TotalE = DirectEfieldCal.EfieldCal(uan, child.Power.Re, child.frequence, child.Position, temp.Position);
                    temp.EX = temp.TotalE.X;
                    temp.EY = temp.TotalE.Y;
                    temp.EZ = temp.TotalE.Z;
                    break;
                case "ReflectionPoint":
                    temp.TotalE = ReflectEfieldCal.ReflectEfield(child.TotalE, child.RayIn, temp.RayIn, child.ReflectionFace.GetVeticalVector(), child.ReflectionFace.conductivity, child.ReflectionFace.permittivity, child.distance, temp.distance, child.frequence);
                    temp.EX = temp.TotalE.X;
                    temp.EY = temp.TotalE.Y;
                    temp.EZ = temp.TotalE.Z;
                    break;
                case "DiffractionPoint":
                    temp.TotalE = DiffractEfiledCal.DiffractEField(child.TotalE, child.RayIn, temp.RayIn, child.distance, temp.distance, child.DiffractionFaces, child.Linea, child.Lineb, child.frequence);
                    temp.EX = temp.TotalE.X;
                    temp.EY = temp.TotalE.Y;
                    temp.EZ = temp.TotalE.Z;
                    break;
                default:
                    break;
            }
        }

        private static void GetPaths(Node root, List<Path> AllPaths, List<PathNode> nodes)
        {
            nodes.Add(new PathNode(root));
            if (!root.IsEnd)
            {
                for (int i = 0; i < root.ChildNodes.Count; i++) GetPaths(root.ChildNodes[i], AllPaths, new List<PathNode>(nodes));
            }
            else
            {
                AllPaths.Add(new Path(nodes));
                //nodes.RemoveAt(nodes.Count - 1);
            }
        }

        //提取所有的路径

        private static List<Path> GetAllPaths(Node root)
        {
            List<Path> Allpaths = new List<Path>();
            List<PathNode> nodes = new List<PathNode>();
            GetPaths(root, Allpaths, nodes);
            return Allpaths;
        }

        #endregion

        //判断是否到达接收点函数

        public static bool ArriveReceive(RayInfo rayin, ReceiveBall receive, Point TerPoint)
        {
            if (Intersection.Distance(rayin.origin, receive.receiver) <= receive.radius) return true;
            else
            {
                List<Point> ballpoint = IsIntersectWithBall(rayin, receive);
                if (ballpoint.Count == 0) return false;
                else if (ArriveReceiveFirst(rayin.origin, TerPoint, NearPoint(ballpoint, rayin))) return true;
                else return false;
            }
        }

        //耗时的地方。。。获取传播路径信息,功率未计算，传播时延在路径筛选后计算,只有到达接收机的路径才计算功率，其他节点不计算功率
        //需要优化能否同时计算多个接收机
        public static void GetTransPath(string Ter, Node child, ReceiveBall receiver, double DiffractionAngle, Node father = null)
        {
            //if (child.Power > 1)
            //{
            //出射射线

            List<RayInfo> rays = GetRays(child, father, DiffractionAngle);

            //追踪出射射线

            List<Pfd> CrossWithTer = new List<Pfd>();
            List<Point> CrossWithReceive = new List<Point>();
            for (int i = 0; i < rays.Count; i++)
            {
                //首先判断发射源与接收机之间的距离时候大于接收球半径，否则不用发射射线直接到达接收机
                if (Intersection.Distance(rays[i].origin, receiver.receiver) > receiver.radius)
                {
                    CrossWithTer = Intersection.IsIntersect(Ter, rays[i].origin, rays[i].RayVector);
                    CrossWithReceive = IsIntersectWithBall(rays[i], receiver);

                    //与地形和接收机均无交点，将子节点设置为FinalPoint类型，IsEnd设为true，IsReceiver为false
                    if (CrossWithTer.Count == 0 && CrossWithReceive.Count == 0)
                    {
                        Node temp = new Node();
                        temp.PointStyle = "FinalPoint"; temp.LayNum = child.LayNum + 1;
                        temp.IsEnd = true; temp.IsReceiver = false;
                        child.ChildNodes.Add(temp);
                        continue;
                    }

                    //与地形无交点，但是到达接收点，计算功率和场强
                    else if (CrossWithTer.Count == 0 && CrossWithReceive.Count != 0)
                    {
                        //判断与接收机交点是否在射线方向上
                        if ((rays[i].RayVector.a / (CrossWithReceive[0].x - child.Position.x)) > 0)
                        {
                            Node temp = new Node(); temp.PointStyle = "Rx"; temp.Position = receiver.receiver;
                            temp.LayNum = child.LayNum + 1; temp.IsReceiver = true; temp.IsEnd = true; temp.RxNum = receiver.RxNum;
                            temp.distance = Intersection.Distance(temp.Position, child.Position); temp.NodeName = receiver.RxName;
                            temp.RayIn = rays[i]; temp.frequence = receiver.frequence; temp.UAN = receiver.UAN; temp.FrequenceWidth = receiver.FrequenceWidth;
                            GetEfield(child.UAN, child, ref temp);
                            //接收点求功率,有问题，电导率和节点常数是面的还是空气的
                            //Face temp1 = Intersection.Isonter(Ter, temp.Position);
                            temp.Power = Power.GetPower(temp.UAN, temp, child);
                            child.ChildNodes.Add(temp);
                            continue;
                        }
                        else
                        {
                            Node temp = new Node();
                            temp.PointStyle = "FinalPoint"; temp.LayNum = child.LayNum + 1;
                            temp.IsEnd = true; temp.IsReceiver = false;
                            child.ChildNodes.Add(temp);
                            continue;
                        }
                    }
                    //与地形有一个交点即为反射点，但不到达接收机
                    else if (CrossWithTer.Count == 1 && CrossWithReceive.Count == 0)
                    {
                        Node temp = new Node(); temp.PointStyle = "ReflectionPoint"; temp.Position = CrossWithTer[0].crosspoint;
                        temp.LayNum = child.LayNum + 1; temp.IsReceiver = false; temp.UAN = child.UAN; temp.FrequenceWidth = child.FrequenceWidth;
                        temp.distance = Intersection.Distance(temp.Position, child.Position);
                        temp.RayIn = rays[i]; temp.frequence = child.frequence; temp.ReflectionFace = CrossWithTer[0].correspond;
                        GetEfield(child.UAN, child, ref temp);
                        //当新节点的层数不小于4时，说明该路径已经过三次反射或绕射，舍弃并追踪下一条射线
                        //将该节点设为end
                        if (temp.LayNum >= 4)
                        {
                            temp.IsEnd = true;
                            child.ChildNodes.Add(temp);
                            continue;
                        }
                        //否则，递归调用该函数继续追踪射线
                        else
                        {
                            temp.IsEnd = false;
                            child.ChildNodes.Add(temp);
                            GetTransPath(Ter, temp, receiver, DiffractionAngle, child);
                        }
                    }

                    //与地形有一个交点即为反射点，而且到达接收机
                    else if (CrossWithTer.Count == 1 && CrossWithReceive.Count != 0)
                    {
                        Node temp = new Node();
                        //射线首先到达接收机
                        if (ArriveReceive(rays[i], receiver, CrossWithTer[0].crosspoint))
                        {
                            temp.PointStyle = "Rx"; temp.Position = receiver.receiver; temp.RxNum = receiver.RxNum;
                            temp.LayNum = child.LayNum + 1; temp.IsReceiver = true; temp.IsEnd = true;
                            temp.distance = Intersection.Distance(temp.Position, child.Position); temp.NodeName = receiver.RxName;
                            temp.RayIn = rays[i]; temp.frequence = receiver.frequence; temp.UAN = receiver.UAN; temp.FrequenceWidth = receiver.FrequenceWidth;
                            GetEfield(child.UAN, child, ref temp);
                            //接收点求功率,有问题，电导率和节点常数是面的还是空气的
                            //Face temp1 = Intersection.Isonter(Ter, temp.Position);
                            temp.Power = Power.GetPower(temp.UAN, temp, child);
                            child.ChildNodes.Add(temp);
                            continue;
                        }
                        else
                        {
                            temp.PointStyle = "ReflectionPoint"; temp.Position = CrossWithTer[0].crosspoint;
                            temp.LayNum = child.LayNum + 1; temp.IsReceiver = false;
                            temp.distance = Intersection.Distance(temp.Position, child.Position);
                            temp.RayIn = rays[i]; temp.frequence = child.frequence; temp.ReflectionFace = CrossWithTer[0].correspond;
                            temp.UAN = child.UAN; temp.FrequenceWidth = child.FrequenceWidth;
                            GetEfield(child.UAN, child, ref temp);
                            //当新节点的层数不小于4时，说明该路径已经过三次反射或绕射，舍弃并追踪下一条射线
                            //将该节点设为end
                            if (temp.LayNum >= 4)
                            {
                                temp.IsEnd = true;
                                child.ChildNodes.Add(temp);
                                continue;
                            }
                            //否则，递归调用该函数继续追踪射线
                            else
                            {
                                temp.IsEnd = false;
                                child.ChildNodes.Add(temp);
                                GetTransPath(Ter, temp, receiver, DiffractionAngle, child);
                            }
                        }
                    }

                    //与地形有2个交点即为绕射点，而且到达接收机
                    else if (CrossWithTer.Count == 2 && CrossWithReceive.Count != 0)
                    {
                        Node temp = new Node();
                        //射线首先到达接收机
                        if (ArriveReceive(rays[i], receiver, CrossWithTer[0].crosspoint))
                        {
                            temp.PointStyle = "Rx"; temp.Position = receiver.receiver; temp.RxNum = receiver.RxNum;
                            temp.LayNum = child.LayNum + 1; temp.IsReceiver = true; temp.IsEnd = true;
                            temp.distance = Intersection.Distance(temp.Position, child.Position); temp.NodeName = receiver.RxName;
                            temp.RayIn = rays[i]; temp.frequence = receiver.frequence; temp.UAN = receiver.UAN; temp.FrequenceWidth = receiver.FrequenceWidth;
                            GetEfield(child.UAN, child, ref temp);
                            //接收点求功率,有问题，电导率和节点常数是面的还是空气的
                            //Face temp1 = Intersection.Isonter(Ter, temp.Position);
                            temp.Power = Power.GetPower(temp.UAN, temp, child);
                            child.ChildNodes.Add(temp);
                            continue;
                        }
                        else
                        {
                            temp.PointStyle = "DiffractionPoint"; temp.Position = CrossWithTer[0].crosspoint;
                            temp.LayNum = child.LayNum + 1; temp.IsReceiver = false;
                            temp.distance = Intersection.Distance(temp.Position, child.Position);
                            temp.RayIn = rays[i]; temp.frequence = child.frequence; temp.DiffractionFaces = new List<Face>() { CrossWithTer[0].correspond, CrossWithTer[1].correspond };
                            List<Point> common = Face.CommonPoints(CrossWithTer[0].correspond, CrossWithTer[1].correspond);
                            temp.Linea = common[0]; temp.Lineb = common[1];
                            temp.UAN = child.UAN; temp.FrequenceWidth = child.FrequenceWidth;
                            GetEfield(child.UAN, child, ref temp);
                            //当新节点的层数不小于4时，说明该路径已经过三次反射或绕射，舍弃并追踪下一条射线
                            //将该节点设为end
                            if (temp.LayNum >= 4)
                            {
                                temp.IsEnd = true;
                                child.ChildNodes.Add(temp);
                                continue;
                            }
                            //否则，递归调用该函数继续追踪射线
                            else
                            {
                                temp.IsEnd = false;
                                child.ChildNodes.Add(temp);
                                GetTransPath(Ter, temp, receiver, DiffractionAngle, child);
                            }
                        }
                    }
                    //与地形有2个交点即为绕射点，但是未到达接收机
                    else if (CrossWithTer.Count == 2 && CrossWithReceive.Count == 0)
                    {
                        Node temp = new Node(); temp.PointStyle = "DiffractionPoint"; temp.Position = CrossWithTer[0].crosspoint;
                        temp.LayNum = child.LayNum + 1; temp.IsReceiver = false;
                        temp.distance = Intersection.Distance(temp.Position, child.Position);
                        temp.RayIn = rays[i]; temp.frequence = child.frequence; temp.DiffractionFaces = new List<Face>() { CrossWithTer[0].correspond, CrossWithTer[1].correspond };
                        List<Point> common = Face.CommonPoints(CrossWithTer[0].correspond, CrossWithTer[1].correspond);
                        temp.Linea = common[0]; temp.Lineb = common[1];
                        temp.UAN = child.UAN; temp.FrequenceWidth = child.FrequenceWidth;
                        GetEfield(child.UAN, child, ref temp);
                        //当新节点的层数不小于4时，说明该路径已经过三次反射或绕射，舍弃并追踪下一条射线
                        //将该节点设为end
                        if (temp.LayNum >= 4)
                        {
                            temp.IsEnd = true;
                            child.ChildNodes.Add(temp);
                            continue;
                        }
                        //否则，递归调用该函数继续追踪射线
                        else
                        {
                            temp.IsEnd = false;
                            child.ChildNodes.Add(temp);
                            GetTransPath(Ter, temp, receiver, DiffractionAngle, child);
                        }
                    }
                }
                else
                {
                    Node temp = new Node(); temp.PointStyle = "Rx"; temp.Position = receiver.receiver;
                    temp.LayNum = child.LayNum + 1; temp.IsReceiver = true; temp.IsEnd = true; temp.RxNum = receiver.RxNum;
                    temp.distance = Intersection.Distance(temp.Position, child.Position); temp.NodeName = receiver.RxName;
                    temp.RayIn = rays[i]; temp.frequence = receiver.frequence; temp.UAN = receiver.UAN; temp.FrequenceWidth = receiver.FrequenceWidth;
                    GetEfield(child.UAN, child, ref temp);
                    //接收点求功率,有问题，电导率和节点常数是面的还是空气的
                    //Face temp1 = Intersection.Isonter(Ter, temp.Position);
                    temp.Power = Power.GetPower(temp.UAN, temp, child);
                    child.ChildNodes.Add(temp);
                    break;
                }
            }
        }

        //提取有效地路径

        public static List<Path> GetLegalPaths(Node root)
        {
            //要再精细筛选，路径所经过的面全部相同的要忽略
            List<Path> LegalPath = new List<Path>();
            List<Path> allpath = GetAllPaths(root);
            List<Path> FinalPath = new List<Path>();
            for (int i = 0; i < allpath.Count; i++)
            {
                if (allpath[i].Rxnum != 0)
                {
                    allpath[i].pathloss = 10 * Math.Log10(allpath[i].node[0].power.GetMag() / allpath[i].node[allpath[i].node.Count - 1].power.GetMag());
                    allpath[i].Delay = allpath[i].GetPathLength() / 300000000;
                    allpath[i].thetaa = ReadUan.GetThetaAngle(allpath[i].node[0].position, allpath[i].node[1].position);
                    allpath[i].thetab = ReadUan.GetThetaAngle(allpath[i].node[allpath[i].node.Count - 2].position, allpath[i].node[allpath[i].node.Count - 1].position);
                    allpath[i].phia = ReadUan.GetPhiAngle(allpath[i].node[0].position, allpath[i].node[1].position);
                    allpath[i].phib = ReadUan.GetPhiAngle(allpath[i].node[allpath[i].node.Count - 2].position, allpath[i].node[allpath[i].node.Count - 1].position);
                    LegalPath.Add(allpath[i]);
                }
            }
            List<Path> Num2 = new List<Path>();
            List<Path> Num3 = new List<Path>();
            List<Path> Num4 = new List<Path>();
            for (int i = 0; i < LegalPath.Count; i++)
            {
                switch (LegalPath[i].node.Count)
                {
                    case 2:
                        Num2.Add(LegalPath[i]);
                        break;
                    case 3:
                        Num3.Add(LegalPath[i]);
                        break;
                    case 4:
                        Num4.Add(LegalPath[i]);
                        break;
                    default:
                        break;
                }
            }
            if (Num2.Count > 0) FinalPath.Add(Num2[0]);
            for (int i = 0; i < Num3.Count - 2; i++)
                for (int j = i + 1; j < Num3.Count - 1; j++)
                {
                    if (Num3[i].node[1].RorDFace == Num3[j].node[1].RorDFace)
                        Num3.RemoveAt(j);
                }
            FinalPath.AddRange(Num3);
            for (int i = 0; i < Num4.Count - 2; i++)
                for (int j = i + 1; j < Num4.Count - 1; j++)
                {
                    if (Num4[i].node[1].RorDFace == Num4[j].node[1].RorDFace && Num4[i].node[2].RorDFace == Num4[j].node[2].RorDFace)
                        Num4.RemoveAt(j);
                }
            FinalPath.AddRange(Num4);
            return FinalPath;
        }
    }
}
//}
